#include "CoCoA/library.H"
#include <sstream>
#include <iostream>
#include <utility>
#include <string>
using namespace CoCoA;
using namespace std; // should do this to use string cout directly


class cpw {
		private: 
			RingElem *pp; // pay attention to the behavior of copy and return 
		public: 
			cpw(string x="x"){
				SparsePolyRing R = NewPolyRing(RingQ(),symbols(x));
				//RingElem p(R); // p=RingElem(R) is wrong!
				pp = new RingElem(R);
			}
			
			cpw(const cpw& p){
				// cout << "copy deconstructor ... " << endl;
				pp = new RingElem((*p.pp));
			}
			
			cpw(RingElem poly) { pp=new RingElem(poly);} 
			
			~cpw(){
				// cout << "calling deconstructor ... " << endl;
				delete pp;
			}

			cpw operator+(const cpw& p) { return *(pp)+*(p.pp);} 

			cpw indets(){
					// error, ring type: *(p.pp) = CoCoA::indets(AsSparsePolyRing(owner(*pp)))[1];
					//*(p.pp) = CoCoA::indets(owner(*pp))[1];
					
					//cpw p(CoCoA::indets(AsSparsePolyRing(owner(*pp)))[1]);
					//return p; segment fault because of index starting from 0

					//cpw *pptr = new cpw(CoCoA::indets(AsSparsePolyRing(owner(*pp)))[1]);
					return CoCoA::indets(AsSparsePolyRing(owner(*pp)))[0];
			}

			cpw& operator=(const cpw& p){
				cout << "assignment ..." << endl;
				delete pp;
				pp=new RingElem(*(p.pp));
				return (*this);
			}

		friend ostream& operator<< (ostream&, const cpw& );
};


ostream& operator<< (ostream& os, const cpw& p){
  os << *(p.pp);
  return os;
}


void program()
{
  GlobalManager CoCoAFoundations;
   
 	cpw 
	p("y");
	//	p="x"; error because there is an assignment member function
	cpw q("x");
	 p=q;
	//p+p.indets(); //cout << p+p.indets()+p.indets() << endl;
	p+p.indets();
	GlobalOutput() << p+ p.indets() +  p.indets() << endl;
}

int main()
{
  try
  {
    program();
    return 0;
  }
  catch (const CoCoA::ErrorInfo& err)
  {
    GlobalErrput() << "***ERROR***  UNCAUGHT CoCoA error";
    ANNOUNCE(err);
  }
  catch (const std::exception& exc)
  {
    GlobalErrput() << "***ERROR***  UNCAUGHT std::exception: " << exc.what() << endl;
  }
  catch(...)
  {
    GlobalErrput() << "***ERROR***  UNCAUGHT UNKNOWN EXCEPTION" << endl;
  }
  return 1;
}
